﻿using System.Xml;
using System;

namespace Toybox.NicoSharp.Video
{
	using Extensions;
	using Primitives;

	public class PacketCreatorV2006 : AbstractPacketCreator
	{

		#region [Static]

		public const string VERSION = "20061206";

		#endregion [Static]


		#region Constructor

		public PacketCreatorV2006(Flv flv)
			: base(flv)
		{
			this.ResFrom = 1000;
			this.When = null;
		}

		#endregion Constructor


		#region Public Members

		public int ResFrom { get; set; }

		public int ClickRevision
		{
			get { return this.Thread == null ? 0 : this.Thread.click_revision; }
		}

		#endregion Public Members


		#region Protected Methods

		protected virtual void AppendUserNode(ref XmlDocument doc)
		{
			XmlNode root = doc.FirstChild;

			string thread = this.Flv.GeneralThreadId;
			int resfrom = this.CoerceResFrom(this.ResFrom);

			if (this.When == null)
			{
				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, null, 0,
					this.Flv.user_id, false, 0, null, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
			else
			{
				WaybackKey waybackKey = new WaybackKey(thread, Flv.Cookies);
				waybackKey.Update();

				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, waybackKey, this.When.Value.GetUnixTime(),
					this.Flv.user_id, false, this.ClickRevision, null, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
		}

		protected virtual void AppendOwnerNode(ref XmlDocument doc)
		{
			XmlNode root = doc.FirstChild;

			string thread = this.Flv.GeneralThreadId;
			int resfrom = this.ResFrom;

			if (this.When == null)
			{
				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, null, 0,
					null, true, -1, null, this.Scores, false, this.LanguageId);

				root.AppendChild(node);
			}
			else
			{
				WaybackKey waybackKey = new WaybackKey(thread, Flv.Cookies);
				waybackKey.Update();

				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, waybackKey, this.When.Value.GetUnixTime(),
					this.Flv.user_id, true, this.ClickRevision, null, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
		}

		protected virtual void AppendCommunityNode(ref XmlDocument doc)
		{
			XmlNode root = doc.FirstChild;

			if (this.CommunityThreadKey == null)
				this.CommunityThreadKey = new ThreadKey(this.Flv.CommunityThreadId, this.Flv.Cookies);

			if (this.CommunityThreadKey.Expired)
				this.CommunityThreadKey.Update();

			string thread = this.Flv.CommunityThreadId;
			int resfrom = this.CoerceResFrom(this.ResFrom);

			if (this.When == null)
			{
				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, null, 0,
					this.Flv.user_id, false, 0, this.CommunityThreadKey, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
			else
			{
				WaybackKey waybackKey = new WaybackKey(thread, Flv.Cookies);
				waybackKey.Update();

				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, waybackKey, this.When.Value.GetUnixTime(),
					this.Flv.user_id, false, this.ClickRevision, this.CommunityThreadKey, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
		}

		protected virtual void AppendScriptNode(ref XmlDocument doc)
		{
			XmlNode root = doc.FirstChild;

			string thread = this.Flv.ScriptThreadId;
			int resfrom = this.CoerceResFrom(this.ResFrom);

			if (this.When == null)
			{
				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, null, 0,
					this.Flv.user_id, false, 0, null, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
			else
			{
				WaybackKey waybackKey = new WaybackKey(thread, Flv.Cookies);
				waybackKey.Update();

				XmlElement node = this.CreateThreadNode(doc,
					thread, VERSION, resfrom, waybackKey, this.When.Value.GetUnixTime(),
					this.Flv.user_id, false, this.ClickRevision, null, this.Scores, this.Nicoru, this.LanguageId);

				root.AppendChild(node);
			}
		}

		protected virtual XmlElement CreateThreadNode(XmlDocument doc,
			string thread, string version, int res_from,
			WaybackKey waybackKey, int when,
			string user_id, bool isFork, int clickRevision,
			ThreadKey threadKey,
			bool isScores, bool isNicoru, int languageId)
		{
			XmlElement node = doc.CreateElement("thread");
			node.SetAttribute("thread", thread);
			node.SetAttribute("version", version);

			if (res_from != 0)
			{
				node.SetAttribute("res_from", (-res_from).ToString());
			}

			if (when != 0)
			{
				node.SetAttribute("waybackkey", waybackKey.Value);
				node.SetAttribute("when", when.ToString());
			}

			if (!string.IsNullOrEmpty(user_id))
			{
				node.SetAttribute("user_id", user_id);
			}

			if (isFork)
			{
				node.SetAttribute("fork", "1");
			}

			if (clickRevision != 0)
			{
				node.SetAttribute("click_revision", clickRevision.ToString());
			}

			if (threadKey != null)
			{
				node.SetAttribute("threadkey", threadKey.Value);
				if (threadKey.Force184)
				{
					node.SetAttribute("force_184", "1");
				}
			}

			if (isScores)
			{
				node.SetAttribute("scores", "1");
			}

			if (isNicoru)
			{
				node.SetAttribute("nicoru", "1");
			}

			if (languageId != 0)
			{
				node.SetAttribute("nicoru", languageId.ToString());
			}

			return node;
		}

		#region Override Methods

		protected override void CreateDocument(ref XmlDocument doc)
		{
			XmlNode root = doc.FirstChild;

			if (this.CheckThreadType(ThreadTypes.User))
				this.AppendUserNode(ref doc);

			if (this.CheckThreadType(ThreadTypes.Owner))
				this.AppendOwnerNode(ref doc);

			if (this.CheckThreadType(ThreadTypes.Community))
				this.AppendCommunityNode(ref doc);

			if (this.CheckThreadType(ThreadTypes.Script))
				this.AppendScriptNode(ref doc);
		}

		#endregion Override Methods

		#endregion Protected Methods

	}
}